home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D+,E-,F-,I+,L+,N-,O-,R+,S+,V+} {place last for debugging}
- {$A+,B-,D-,E-,F-,I+,L-,N-,O-,R-,S-,V+} {place last for normal use}
-
- {$M 4096,0,655360}
-
- program DifEdl;
-
- const
- NAME_AND_VERSION = 'DifEdl Version 1.0 of December 07, 1988';
-
- {****************************************************************************}
- {
- This program was written by Carley Phillips for Longhorn Systems, Inc., and
- and is hereby placed in the PUBLIC DOMAIN with no support whatsoever.
- However, user comments and bug reports are welcome and should be directed
- to Carley Phillips on CompuServe at User ID 76630,3312.
- }
- {****************************************************************************}
- {
- DifEdl compares two text files, and OldFile and a NewFile, and produces
- a list of the differences on standard output (which may, of course, be
- re-directed to a file). The difference list is in a special format
- acceptable as input to EDLIN, the editor supplied with all versions of
- DOS. In particular, if you execute
-
- "DifEdl old\MyFile new\MyFile >MyFile.DED"
-
- you will then be able to execute
-
- "EdLin old\MyFile <MyFile.DED >EdlFile"
-
- The result will be that EdLin will update the old MyFile so that it is
- identical to the new MyFile. The purpose of re-directing the output of
- EdLin to EdlFile is so you can use an editor or file browser to verify
- that the lines deleted were the correct lines. This is possible because
- of an unusual feature of DifEdl explained below.
-
- This program was written to allow publishing changes and enhancements to
- proprietary files without posting the proprietary files themselves.
- Suppose, for example, you have made some major enhancements to the Turbo
- Graphics Toolbox that you wish to share. By using DifEdl to produce a file
- containing only your changes, you could then post only the change file on
- bulletin boards and thus offend no one.
-
- Obviously it's just a suggestion, but we always use the extension of "ded"
- to indicate difference files produced from DifEdl. That extension is not]
- in common use, and it helps to identify what file is expected to be updated.
-
- An interesting feature of the difference file is it not only includes
- delete and insert instructions plus the added lines, but also includes all
- lines DELETED from the original file. This is done in such a way that you
- may view both the added lines and the deleted lines in the difference file
- with your favorite editor or file browser and update your old file manually
- if desired.
-
- However, the fact that deleted lines are included in the difference file has
- another benefit: assuming you use EdLin to apply the updates, you will be
- able to re-direct the screen output of EdLin to still another file for
- review. This EdLin output file will show not only insertions, but also the
- lines actually deleted and the lines that SHOULD have been deleted for
- comparison. This is useful if you're not sure if your "original" matches
- the one from which the MyFile.Ded was created.
-
- Five options may appear after the file names: /R#, /D#, /M#, /B#, and /N
- where # is a number.
- /R allows changing the number of successive lines that must match in order
- to re-acquire synchronization after a mis-match is detected. The default
- value is 5.
- /D allows changing the number of successive lines that must match after
- a very small (less than /R# lines) file difference has been found.
- The default value is 1.
- /M allows changing the maximum line size from 253 to some other number
- so that more lines may be kept in memory. This is useful when you have
- two files that are different for an extrememly long series of lines. If
- you get a message indicating that the files are too different, try /M to
- set the maximum line size to the actual length of the longest line in
- your files. Note EdLin has a maximum line length of 253.
- /B allows changing the block size used to keep EdLin's internal buffer
- from overflowing. While EdLin can edit a file of any size, only a
- part of a large file is kept in memory at one time. Periodically,
- it is necessary to write the early part of the buffer and append new
- lines from the input file. The default value for /B, 500, specifies
- that the buffer should be written after every 500 lines are processed.
- This value should suffice for most files you will encounter. If the
- file has extremely long lines, then use /B to specify a smaller value
- such as 250.
- /N turns off the special feature of placing the deleted lines in the
- difference file although it will not prevent EdLin from listing the
- lines to be deleted just before they are actually deleted.
-
- There are two possible options that are not enabled in the standard version
- because 1) they slow down the processing, 2) they require extra space, and
- 3) they are not normally required. Both options are primarily for special
- purpose use by users who somehow managed to mix both spaces and tabs within
- their various versions of a program, or perhaps have run a program formatter
- on their code and have thus significantly changed the white space distribution.
- If you enable these options, /L and /W, by DEFINEing the compiler directive
- WHITEOPTIONS below, then
-
- /L will consider two lines identical even if their leading white space
- (tabs and spaces) are different.
-
- /W will consider two lines identical even if their imbedded white spaces
- are different. One word of caution. If using /W, be aware that quoted
- white space is still reduced to a single space for the purposes of
- comparison. This means that /W would prevent discovering the
- difference between, for example, mystr := ' ' and mystr := ' '.
-
- NOTE ABOUT EDLIN AND LARGE FILES
- All EdLin's from DOS version 3.0 through 3.3 that have been tested recently
- have a bug relating to the editing of large files. EdLin is supposed to read
- lines only until its buffer is 3/4 full. However, instead it reads lines
- until the buffer is completely full. This means insertions cannot be done
- near the beginning of the file and any attempt to make insertions early will
- result in an "insufficient memory" message. The obvious solution is to get
- a corrected version of EdLin from Microsoft. However, Microsoft has informed
- me that the only way to do this is to buy DOS 4.0.
-
- Here's an alternative solution. You may skip the rest of this documentation
- section until you want to DifEdl on a large file (greater than about 48k)
- and it will have insertions in the first 48k.
-
- First, create a text file of your own (say, DUMMY) that contains, say, 100
- full lines (say about 70 characters each). Make sure you know exactly how
- many lines are in DUMMY. (Don't try to help by making this file too big.
- DifEdl assumes there are always more than /B# lines left in the buffer.)
-
- Secondly, prepend this file onto the file (say, TOBEFIXD.DOC) that is to be
- updated with the output of DifEdl (say, TOBEFIXD.DED) by using
-
- "copy DUMMY+TOBEFIXD.DOC TOBEFIXD.NEW"
-
- Thirdly, edit the file TOBEFIXD.DED and insert the single line "1,100d" as
- the first line.
-
- Finally, use the modified TOBEFIXD.DED to edit TOBEFIXD.NEW using
-
- "EdLin TOBEFIXD.NEW <TOBEFIXD.DED >EDLFILE"
-
- The result will be that the buggy EdLin erroneously fills its buffer with
- the first part of TOBEFIXD.NEW. However, the text read will include your
- added 100 lines from DUMMY. The new first line in the modified TOBEFIXD.DED
- will delete these extraneous lines, thus freeing some buffer space. At that
- point, the rest of the edit will usually proceed normally. You can verify
- this by looking at the output of the edit in EDLFILE and making sure there
- are no error messages.
- }
- {****************************************************************************}
- {$DEFINE WHITEOPTIONS} {Place last to enable "ignore white space" options}
- {$UNDEF WHITEOPTIONS} {Place last to disable "ignore white space" options}
-
- type
- t_Str = string[255]; {used for all strings except those from files}
-
- t_StrPtr = ^t_Str; {and these will let us find them on the heap}
-
- const
- DEFAULT_RESYNC = 5; {default for NumToResync}
- DEFAULT_SMALL = 1; {default for SmallDiffs}
- DEFAULT_MAX_LEN = 253; {default for MaxLineLen = max line for EdLin}
- DEFAULT_BLOCK = 500; {default for EdLinBlock}
-
- {$IFNDEF WHITEOPTIONS}
- NUM_ARRAYS = 2; {only need one copy of old line and new line}
- {$ELSE}
- NUM_ARRAYS = 4; {need original and reduced copy of both old and new lines}
- {$ENDIF}
- {most of data segment is for 3 or 5 arrays for line number and pointers}
- MAX_LINES = 64000 div (sizeof(longint) + (NUM_ARRAYS * sizeof(t_StrPtr)));
- MAX_LINESM1 = MAX_LINES - 1; {used for array dimensions below}
- DEFAULT_STR = #$0D#$0A; {this string can never show up from ReadLn}
- HEAP_RESERVE = 2000; {used for calculation which allocates heap}
- MIN_NUM_IN_BUF = 25; {must end up with room for at least this many}
- TEXT_BUF_SIZE = 8192; {used for readln of oldfile and newfile}
-
- var
- OldLineNum : array [0..MAX_LINESM1] of longint; {old file line numbers}
- OldStrPtr : array [0..MAX_LINESM1] of t_StrPtr; {pointers to old lines}
- NewStrPtr : array [0..MAX_LINESM1] of t_StrPtr; {pointers to new lines}
- {$IFDEF WHITEOPTIONS}
- OldTrmPtr : array [0..MAX_LINESM1] of t_StrPtr; {pointers to old trimmed}
- NewTrmPtr : array [0..MAX_LINESM1] of t_StrPtr; {pointers to new trimmed}
- {$ENDIF}
-
- NumToResync : word; {number of successive matches to recover sync}
- SmallDiffs : word; {number to resync if differences are small}
- MaxLineLen : word; {maximum line length accepted}
- EdLinBlock : word; {size of EdLin write/append blocks}
-
- NumInBuf : word; {number of items actually in the 3/5 line arrays}
- MaxToSearch : word; {maximum number of items to search}
- OldFile : text; {the old input file}
- NewFile : text; {the new input file}
- OldNextIn : word; {array index for placing next old line read}
- NewNextIn : word; {array index for placing next new line read}
- OldNextOut : word; {array index for next old line to examine}
- NewNextOut : word; {array index for next new line to examine}
- OldInBuf : word; {count of number of old file lines in buffer}
- NewInBuf : word; {count of number of new file lines in buffer}
- OldLineCnt : longint; {counter for original line numbers in old file}
- NewLineCnt : longint; {counter for original line numbers in new file}
- ConFile : text; {for console output in case stdout redirected}
- NeedNewLine : boolean; {if abort, then clean up old line before message}
- OutputDel : boolean; {include deleted lines in the difference output}
-
- {$IFDEF WHITEOPTIONS}
- TrimLeading : boolean; {remove all leading white space}
- TrimAllWhite: boolean; {convert all white space to single space}
-
- const
- tabchr = #$09;
- {$ENDIF}
-
- {****************************************************************************}
- {display usage information and halt}
- procedure Usage;
- begin
- writeln (ConFile, #$07);
- write (ConFile, 'USAGE: DifEdl oldfile newfile [/R#] [/D#] [/M#] [/B#] ');
- {$IFDEF WHITEOPTIONS}
- write (ConFile, '[/W] [/L] ');
- {$ENDIF}
- writeln (ConFile, '[>diffile]');
- writeln (ConFile);
- writeln (ConFile, '/R# ( 5) -- number of consecutive lines that must match to re-sync (2-20)');
- writeln (ConFile, '/D# ( 1) -- number of lines to match when small difference is found (1-/R)');
- writeln (ConFile, '/M# ( 253) -- maximum line length (1-255)');
- writeln (ConFile, '/B# ( 500) -- size of EdLin write/append sequences (100-1000)');
- writeln (ConFile, '/N -- do not include deleted lines in the output');
- {$IFDEF WHITEOPTIONS}
- writeln (ConFile, '/W ( off) -- compare with all groups of white space changed to single spaces');
- writeln (ConFile, '/L ( off) -- compare with all leading white space eliminated');
- {$ENDIF}
- halt (1);
- end; {Usage}
-
- {****************************************************************************}
- procedure Abort (msg : t_Str);
- begin
- if (NeedNewLine) then
- writeln (ConFile);
- writeln (ConFile, #$07, msg);
- halt(254);
- end; {Abort}
-
- {****************************************************************************}
- {increment an array index, wrapping to the beginning if necessary}
- function IncNdx (ndx : word;
- incr : word
- ) : word;
- {the body of this function was converted so that it is an inline directive}
- {
- begin
- inc (ndx, incr);
- if (ndx < NumInBuf) then
- IncNdx := ndx
- else
- IncNdx := ndx - NumInBuf;
- end;
- }
- Inline(
- $58/ { pop ax ;get index}
- $5B/ { pop bx ;get increment}
- $01/$D8/ { add ax,bx ;increment index}
- $3B/$06/>NUMINBUF/ { cmp ax,[>NumInBuf];check it}
- $7C/$04/ { jl out ;skip if ok}
- $2B/$06/>NUMINBUF { sub ax,[>NumInBuf];wrap index}
- ); {out: ;label for end}
-
- {****************************************************************************}
- {$IFDEF WHITEOPTIONS}
- {remove leading white space and/or reduce all white space sequences to 1 space}
- function ReduceWhiteSpace (tstr : t_Str
- ) : t_Str;
- var
- ndx : integer;
- begin
- if (TrimLeading) then
- begin
- while ((length(tstr) > 0) and
- ((tstr[1] = ' ') or (tstr[1] = tabchr))) do
- delete (tstr, 1, 1);
- end;
- if (not TrimAllWhite) then
- begin
- ReduceWhiteSpace := tstr;
- exit;
- end;
- {first convert all spaces to tabs}
- ndx := pos (' ', tstr);
- while (ndx > 0) do
- begin
- tstr[ndx] := tabchr;
- ndx := pos (' ', tstr);
- end;
- {now convert all series of tabs to a single space}
- ndx := pos (tabchr, tstr);
- while (ndx > 0) do
- begin
- tstr[ndx] := ' ';
- while ((ndx < length(tstr)) and (tstr[ndx+1] = tabchr)) do
- delete (tstr, ndx+1, 1);
- ndx := pos (tabchr, tstr);
- end;
- ReduceWhiteSpace := tstr;
- end; {ReduceWhiteSpace}
- {$ENDIF}
-
- {****************************************************************************}
- procedure GetOldRecord;
- var
- tempstr : t_Str;
- ndx : word;
- tempndx : word;
- begin
- if (not eof(OldFile)) then
- begin
- inc(OldLineCnt);
- OldLineNum[OldNextIn] := OldLineCnt;
- Readln (OldFile, tempstr);
- if (length(tempstr) > MaxLineLen) then
- Abort ('Old file contains lines that are too long');
- OldStrPtr[OldNextIn]^ := tempstr;
- {$IFDEF WHITEOPTIONS}
- OldTrmPtr[OldNextIn]^ := ReduceWhiteSpace (tempstr);
- {$ENDIF}
- OldNextIn := IncNdx (OldNextIn,1);
- inc (OldInBuf);
- end;
- if (eof(Oldfile)) then
- for ndx := 0 to pred(NumToResync) do
- begin
- tempndx := IncNdx (OldNextIn, ndx);
- OldLineNum[tempndx] := succ(OldLineCnt) + ndx;
- OldStrPtr[tempndx]^ := DEFAULT_STR;
- {$IFDEF WHITEOPTIONS}
- OldTrmPtr[tempndx]^ := DEFAULT_STR;
- {$ENDIF}
- end;
- end; {GetOldRecord}
-
- {****************************************************************************}
- procedure GetNewRecord;
- var
- tempstr : t_Str;
- ndx : word;
- tempndx : word;
- begin
- if (not eof(NewFile)) then
- begin
- inc(NewLineCnt);
- Readln (NewFile, tempstr);
- if (length(tempstr) > MaxLineLen) then
- Abort ('New file contains lines that are too long');
- NewStrPtr[NewNextIn]^ := tempstr;
- {$IFDEF WHITEOPTIONS}
- NewTrmPtr[NewNextIn]^ := ReduceWhiteSpace (tempstr);
- {$ENDIF}
- NewNextIn := IncNdx (NewNextIn,1);
- inc (NewInBuf);
- end;
- if (eof(NewFile)) then
- for ndx := 0 to pred(NumToResync) do
- begin
- tempndx := IncNdx (NewNextIn, ndx);
- NewStrPtr[tempndx]^ := DEFAULT_STR;
- {$IFDEF WHITEOPTIONS}
- NewTrmPtr[tempndx]^ := DEFAULT_STR;
- {$ENDIF}
- end;
- end; {GetNewRecord}
-
- {****************************************************************************}
- {process command line options that follow file names}
- procedure ProcessOptions (var ShowInfo : boolean);
- var
- ndx : integer;
- tempstr : t_Str;
- retcode : integer;
- begin
- NumToResync := DEFAULT_RESYNC;
- SmallDiffs := DEFAULT_SMALL;
- MaxLineLen := DEFAULT_MAX_LEN;
- EdLinBlock := DEFAULT_BLOCK;
- OutputDel := true;
- {$IFDEF WHITEOPTIONS}
- TrimLeading := false;
- TrimAllWhite := false;
- {$ENDIF}
- ShowInfo := false;
- if (ParamCount > 2) then
- for ndx := 3 to ParamCount do
- begin
- tempstr := ParamStr(ndx);
- if (tempstr[1] = '/') then
- case upcase(tempstr[2]) of
- 'R': begin
- delete (tempstr, 1, 2);
- val (tempstr, NumToResync, retcode);
- if ((retcode <> 0) or
- (NumToResync < 2) or
- (NumToResync > 20) ) then
- begin
- writeln (ConFile, 'Invalid resync value');
- Usage;
- end;
- end;
- 'D': begin
- delete (tempstr, 1, 2);
- val (tempstr, SmallDiffs, retcode);
- if ((retcode <> 0) or
- (SmallDiffs < 1) or
- (SmallDiffs > 20) ) then
- begin
- writeln (ConFile, 'Invalid small difference sync value');
- Usage;
- end;
- end;
- 'M': begin
- delete (tempstr, 1, 2);
- val (tempstr, MaxLineLen, retcode);
- if ((retcode <> 0) or
- (MaxLineLen < 1) or
- (MaxLineLen > 255) ) then
- begin
- writeln (ConFile, 'Invalid maximum line length');
- Usage;
- end;
- end;
- 'B': begin
- delete (tempstr, 1, 2);
- val (tempstr, EdLinBlock, retcode);
- if ((retcode <> 0) or
- (EdLinBlock < 100) or
- (EdLinBlock > 1000) ) then
- begin
- writeln (ConFile, 'Invalid EdLin write/append block size');
- Usage;
- end;
- end;
- 'I': ShowInfo := true;
- 'N': OutputDel := false;
- {$IFDEF WHITEOPTIONS}
- 'W': TrimAllWhite := true;
- 'L': TrimLeading := true;
- {$ENDIF}
- else begin
- writeln (ConFile, 'Invalid command line option');
- Usage;
- end;
- end;
- end;
- if (SmallDiffs > NumToResync) then
- begin
- writeln (ConFile, 'Invalid small difference sync value');
- Usage;
- end;
- end; {ProcessOptions}
-
- {****************************************************************************}
- {initialize everything}
- procedure Initialize;
- var
- OldName : t_Str;
- NewName : t_Str;
- ndx : integer;
- MaxToRead : word;
- ShowInfo : boolean;
- BufferPtr : pointer;
- LongNumInBuf : longint;
- begin
- assign (ConFile, 'CON');
- rewrite (ConFile);
- writeln (ConFile, NAME_AND_VERSION);
-
- {handle file names}
- if (ParamCount < 2) then
- Usage;
- OldName := ParamStr (1);
- assign (OldFile, OldName);
- {$I-} reset (OldFile); {$I+}
- if (IOResult <> 0) then
- Abort ('Cannot open old file');
- if (MaxAvail < TEXT_BUF_SIZE) then
- Abort ('Cannot allocate old file text buffer');
- GetMem (BufferPtr, TEXT_BUF_SIZE);
- SetTextBuf (OldFile, BufferPtr^, TEXT_BUF_SIZE);
-
- NewName := ParamStr(2);
- assign (NewFile, NewName);
- {$I-} reset (NewFile); {$I+}
- if (IOResult <> 0) then
- Abort ('Cannot open new file');
- if (MaxAvail < TEXT_BUF_SIZE) then
- Abort ('Cannot allocate new file text buffer');
- GetMem (BufferPtr, TEXT_BUF_SIZE);
- SetTextBuf (NewFile, BufferPtr^, TEXT_BUF_SIZE);
-
- ProcessOptions (ShowInfo);
-
- {set up the circular line buffers}
- LongNumInBuf := (MaxAvail - HEAP_RESERVE) div (NUM_ARRAYS * succ(MaxLineLen));
- if (LongNumInBuf > MAX_LINES) then
- LongNumInBuf := MAX_LINES;
- NumInBuf := LongNumInBuf;
- if (NumInBuf < (MIN_NUM_IN_BUF + NumToResync + NumToResync)) then
- Abort ('Not enough memory for adequate line buffers');
- MaxToRead := NumInBuf - NumToResync; {always leave room for filler}
- MaxToSearch := MaxToRead - NumToResync; {make sure have match past end}
-
- for ndx := 0 to pred(NumInBuf) do
- begin
- OldLineNum[ndx] := succ(ndx);
- if (MaxAvail < succ(MaxLineLen)) then
- Abort ('Error in memory allocation algorithm');
- getmem (OldStrPtr[ndx], succ(MaxLineLen));
- OldStrPtr[ndx]^ := DEFAULT_STR;
- if (MaxAvail < succ(MaxLineLen)) then
- Abort ('Error in memory allocation algorithm');
- getmem (NewStrPtr[ndx], succ(MaxLineLen));
- NewStrPtr[ndx]^ := DEFAULT_STR;
- {$IFDEF WHITEOPTIONS}
- if (MaxAvail < succ(MaxLineLen)) then
- Abort ('Error in memory allocation algorithm');
- getmem (OldTrmPtr[ndx], succ(MaxLineLen));
- OldTrmPtr[ndx]^ := DEFAULT_STR;
- if (MaxAvail < succ(MaxLineLen)) then
- Abort ('Error in memory allocation algorithm');
- getmem (NewTrmPtr[ndx], succ(MaxLineLen));
- NewTrmPtr[ndx]^ := DEFAULT_STR;
- {$ENDIF}
- end;
-
- {fill the old file buffer}
- OldNextIn := 0;
- OldNextOut := 0;
- OldLineCnt := 0;
- OldInBuf := 0;
- while ((not eof(OldFile)) and (OldNextIn < MaxToRead)) do
- GetOldRecord;
-
- {fill the new file buffer}
- NewNextIn := 0;
- NewNextOut := 0;
- NewLineCnt := 0;
- NewInBuf := 0;
- while ((not eof(NewFile)) and (NewNextIn < MaxToRead)) do
- GetNewRecord;
-
- if (ShowInfo) then
- begin
- writeln (ConFile, 'There is room for ', NumInBuf, ' lines of ',
- MaxLineLen, ' characters in each of ',
- NUM_ARRAYS, ' arrays.');
- writeln (ConFile, 'The initial read obtained ', OldInBuf,
- ' old records and ', NewInBuf, ' new records.');
- writeln (ConFile, 'Re-sync values are ', NumToResync, ' and ',
- SmallDiffs, ' and the EdLin block size is ', EdLinBlock, '.');
- end;
- end; {Initialize}
-
- {****************************************************************************}
- {checks if the next sync lines match}
- function CheckSync (sync : word;
- onum : word;
- nnum : word
- ) : boolean;
- var
- ndx : word;
- begin
- checksync := false;
- for ndx := 0 to pred(sync) do
- {$IFNDEF WHITEOPTIONS}
- if (OldStrPtr[IncNdx(OldNextOut,onum+ndx)]^ <>
- NewStrPtr[IncNdx(NewNextOut,nnum+ndx)]^) then
- exit;
- {$ELSE}
- if (OldTrmPtr[IncNdx(OldNextOut,onum+ndx)]^ <>
- NewTrmPtr[IncNdx(NewNextOut,nnum+ndx)]^) then
- exit;
- {$ENDIF}
- checksync := true;
- end; {CheckSync}
-
- {****************************************************************************}
- {slide the buffers against each other trying to find sync successive matches}
- procedure RecoverSync ( sync : word;
- var oldcnt : word;
- var newcnt : word
- );
- var
- outerndx : word;
- innerndx : word;
- maxndx : word;
- begin
- if (OldInBuf > NewInBuf) then
- maxndx := succ(OldInBuf) {this is actually one too many}
- else
- maxndx := succ(NewInBuf); {this is actually one too many}
- if (maxndx > MaxToSearch) then
- maxndx := MaxToSearch; {need to allow data or filler past end}
- for outerndx := 0 to pred(maxndx) do
- for innerndx := 0 to outerndx do
- begin
- {actually checks one past end and will find filler as last resort}
- if ((outerndx <= OldInBuf) and
- (innerndx <= NewInBuf)) then
- begin
- if (checksync (sync, outerndx, innerndx)) then
- begin
- oldcnt := outerndx;
- newcnt := innerndx;
- exit;
- end;
- end;
- {actually checks one past end and will find filler as last resort}
- if ((innerndx <> outerndx) and
- (innerndx <= OldInBuf) and
- (outerndx <= NewInBuf)) then
- begin
- if (checksync (sync, innerndx, outerndx)) then
- begin
- oldcnt := innerndx;
- newcnt := outerndx;
- exit;
- end;
- end;
- end;
- Abort ('Cannot recover synchronization -- files too different');
- end; {RecoverSync}
-
- {****************************************************************************}
- {remove one line from the old buffer and try to read a replacement from file}
- procedure AdvanceOld;
- begin
- OldNextOut := IncNdx (OldNextOut, 1);
- dec (OldInBuf);
- GetOldRecord;
- end; {AdvanceOld}
-
- {****************************************************************************}
- {remove one line from the new buffer and try to read a replacement from file}
- procedure AdvanceNew;
- begin
- NewNextOut := IncNdx (NewNextOut, 1);
- dec (NewInBuf);
- GetNewRecord;
- end; {AdvanceNew}
-
- {****************************************************************************}
- {control the process of comparing the files against each other}
- procedure ComparEm;
- var
- NextDot : longint;
- OldLineBias : longint;
- oldcnt : word;
- newcnt : word;
- tempold : word;
- tempnew : word;
- tbeg : word;
- tend : word;
- count : word;
- AllMatch : boolean;
- begin
- AllMatch := true;
- NeedNewLine := true;
- NextDot := 0;
- OldLineBias := 0;
- {loop while there are any lines left in either buffer}
- while ((OldNextOut <> OldNextIn) or (NewNextOut <> NewNextIn)) do
- begin
- if (OldLineNum[OldNextOut] > NextDot) then
- begin
- write (ConFile, '.');
- inc(NextDot,100);
- end;
- {check if the current lines in each buffer match}
- {$IFNDEF WHITEOPTIONS}
- if (OldStrPtr[OldNextOut]^ = NewStrPtr[NewNextOut]^) then
- {$ELSE}
- if (OldTrmPtr[OldNextOut]^ = NewTrmPtr[NewNextOut]^) then
- {$ENDIF}
- begin
- {the lines match, so just skip them}
- AdvanceOld;
- AdvanceNew;
- end
- else
- begin
- {the lines don't match, so recover sync}
- AllMatch := false;
- RecoverSync (NumToResync, oldcnt, newcnt);
- {if the change was only a small addition and/or deletion}
- if ((SmallDiffs < NumToResync) and
- (oldcnt < NumToResync) and
- (newcnt < NumToResync)) then
- {then the following statement handles small changes better}
- {when the small changes are closely grouped together}
- RecoverSync (SmallDiffs, oldcnt, newcnt);
- {loop while there's any lines left to delete or insert}
- while ((oldcnt > 0) or (newcnt > 0)) do
- begin
- {this code splits big updates into small chunks for EdLin}
- if (oldcnt > EdLinBlock) then
- tempold := EdLinBlock
- else
- tempold := oldcnt;
- if (newcnt > EdLinBlock) then
- tempnew := EdLinBlock
- else
- tempnew := newcnt;
- dec (oldcnt, tempold);
- dec (newcnt, tempnew);
-
- {move lines through EdLin's buffer to handle large files}
- while ((OldLineNum[OldNextOut] + OldLineBias) > EdLinBlock) do
- begin
- writeln (EdLinBlock,'WA');
- dec (OldLineBias, EdLinBlock)
- end; {while}
-
- {the lines skipped in the old buffer are to be deleted}
- {list and delete the lines, then insert and remove what}
- {SHOULD have been deleted for comparison}
- if (tempold > 0) then
- begin
- tbeg := OldLineNum[OldNextOut] + OldLineBias;
- tend := tbeg + tempold - 1;
- write (tbeg, ',', tend, 'L '); {list lines}
- writeln (tbeg, ',', tend, 'D'); {delete them}
- if (OutputDel) then
- writeln (tbeg, 'I ', tbeg, ',', tend, 'D');
- for count := 1 to tempold do
- begin
- if (OutputDel) then
- writeln (OldStrPtr[OldNextOut]^);
- AdvanceOld;
- end;
- if (OutputDel) then
- write (#$03);
- dec (OldLineBias, tempold);
- end; {if tempold}
-
- {the lines skipped in the new buffer are to be inserted}
- if (tempnew > 0) then
- begin
- writeln (OldLineNum[OldNextOut] + OldLineBias, 'I');
- for count := 1 to tempnew do
- begin
- writeln (NewStrPtr[NewNextOut]^);
- AdvanceNew;
- end;
- write (#$03);
- inc (OldLineBias, tempnew);
- end; {if tempnew}
- end; {while}
- end; {else}
- end; {while}
- writeln (ConFile);
- NeedNewLine := false;
- if (not AllMatch) then
- writeln ('E')
- else
- writeln (ConFile, 'No differences were found.');
- end; {CompareEm}
-
- {****************************************************************************}
- procedure FinishUp;
- begin
- close (OldFile);
- close (NewFile);
- end; {FinishUp}
-
- {****************************************************************************}
- begin
- Initialize;
- ComparEm;
- FinishUp;
- end.